package weibo.crawler;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

import predict.automata.InterestItem;

import data.process.ProcessData;
import data.process.UO.FriendshipUO;
import data.process.UO.FriendshipUODAO;
import data.process.UO.InterestUO;
import data.process.UO.InterestUODAO;
import data.process.UO.UserUO;
import data.process.UO.UserUODAO;

import weibo.crawler.UO.CommentUO;
import weibo.crawler.UO.CommentUODAO;
import weibo.crawler.UO.RawStatusUO;
import weibo.crawler.UO.RawStatusUODAO;
import weibo.crawler.UO.RawUserUO;
import weibo.crawler.UO.RawUserUODAO;
import weibo.crawler.UO.RepostsUO;
import weibo.crawler.UO.RepostsUODAO;
import weibo4j.Comments;
import weibo4j.Friendships;
import weibo4j.Oauth;
import weibo4j.Timeline;
import weibo4j.Users;
import weibo4j.Weibo;
import weibo4j.examples.Log;
import weibo4j.model.Comment;
import weibo4j.model.Paging;
import weibo4j.model.PostParameter;
import weibo4j.model.Status;
import weibo4j.model.User;
import weibo4j.model.WeiboException;
import weibo4j.util.BareBonesBrowserLaunch;
import weibo4j.util.WeiboConfig;


public class Crawler {
	private Weibo weibo = new Weibo();
	private Oauth oauth = new Oauth();
	private String code = "";
	private String access_token = "";
	
//	private RawUserUODAO rawuserDao = new RawUserUODAO();
//	private RawUserUO rawuserUO = new RawUserUO();
//	private FriendshipUODAO  friendshipDao = new FriendshipUODAO();
//	private FriendshipUO friendshipUO = new FriendshipUO();
//	private UserUODAO userDao = new UserUODAO();
//	private UserUO userUO = new UserUO();
//	private InterestUO interestUO = new InterestUO();
//	private InterestUODAO interestDao = new InterestUODAO();
	private ProcessData processData = new ProcessData();
	
	public Crawler() throws WeiboException, IOException{
		if (code.equals("")) {
			BareBonesBrowserLaunch.openURL(oauth.authorize("code"));
			System.out.print("Hit enter when it's done.[Enter]:");
			BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
			code = br.readLine();
			Log.logInfo("code: " + code);
		}
		access_token = oauth.getAccessTokenByCode(code).getAccessToken();
		weibo.setToken(access_token);
	}
	
	public UserUO getUserUO(String uid) throws WeiboException{
		UserUODAO userDao = new UserUODAO();
		List<UserUO> list = userDao.findByUid(uid);
		if (list.size() == 0) {
			this.crawlUser(uid);
		}
		return (UserUO) userDao.findByUid(uid).get(0);
	}
	
	public RawUserUO getRawUserUO(String uid) throws WeiboException {
		RawUserUODAO rawuserDao = new RawUserUODAO();
		if (rawuserDao.findByUid(uid).size() == 0) {
			this.crawlUser(uid);
		}
		return (RawUserUO) rawuserDao.findByUid(uid).get(0);
	}
	
	private void crawlUser(String uid) throws WeiboException{
		RawUserUODAO rawuserDao = new RawUserUODAO();
		RawUserUO rawuserUO = new RawUserUO();
		UserUO userUO = new UserUO();
		UserUODAO userDao = new UserUODAO();
		User user;
		user = (new Users()).showUserById(uid);
		rawuserUO.setUser(user);
		rawuserDao.save(rawuserUO);
		userUO.setUid(uid);
		userUO.setActiveDegree(processData.computeActivityDegree(uid));
		userUO.setInfluenceDegree(processData.computeInfluenceDegree(uid));
		userDao.save(userUO);

	}
	
	public InterestUO getInterestUO(String uid, InterestItem item) {
		InterestUODAO interestDao = new InterestUODAO();
		List<InterestUO> list = interestDao.findByUid(uid);
		if (list.size() == 0) {
			this.crawlInterest(uid, item);
			list = interestDao.findByUid(uid);
		}
		for (InterestUO l : list) {
			if (l.getInterestItem() == item.toString()) {
				return l;
			}
		}
		InterestUO l = new InterestUO();
		l.setUid(uid);
		l.setInterestItem(item.toString());
		l.setInterestDegree(this.crawlInterest(uid, item));
		return l;
	}
	
	private double crawlInterest(String uid, InterestItem item) {
		InterestUO interestUO = new InterestUO();
		InterestUODAO interestDao = new InterestUODAO();
		interestUO.setUid(uid);
		interestUO.setInterestItem(item.toString());
		double interestDegree = processData.computeInterestDegree(uid, item);
		interestUO.setInterestDegree(interestDegree);
		interestDao.save(interestUO);
		return interestDegree;
	}
	
	/**
	 * 根据uid获取该用户的最多5000个粉丝的uid
	 * @param uid
	 * @return List<User>
	 * @throws WeiboException
	 */
	public List<String> getAllFollowers(String uid) {
		//先从数据库中查找，如果找到直接寻回，如果没有再抓取
		FriendshipUODAO friendshipDao = new FriendshipUODAO();
		List<FriendshipUO> friends = friendshipDao.findByUid(uid);
		List<String> friendsUidList = new ArrayList<String>();
		if (friends.size() == 0) {
			this.crawlAllFollowers(uid);
		}
		for (FriendshipUO friend : friends) {
			friendsUidList.add(friend.getFollowid());
		}
		return friendsUidList;
		
	}
	
	/**
	 * 爬取指定用户的所有粉丝，存进数据库
	 * @param uid
	 * @throws WeiboException 
	 */
	private void crawlAllFollowers(String uid) {
		User user;
		try {
			user = (new Users()).showUserById(uid);
			int totalCount = user.getFollowersCount();
			if (totalCount > 5) {
				totalCount = 5;
			}
			Friendships fm = new Friendships();
			List<User> followers = new ArrayList<User>();
			int cursor = 1;
			for (int cnt = 0; cnt <= totalCount; cnt = cnt+200) {
				followers = fm.getFollowersById(uid, 5, cursor++);
				for(User u : followers) {
					Log.logDebug(u.toString());
					saveFriendshipUO(uid, u.getId());
				}			
			}
		} catch (WeiboException e) {
		}
	}
	
	private void saveFriendshipUO(String uid, String followId) {
		FriendshipUODAO friendshipDao = new FriendshipUODAO();
		double influenceDegree = processData.computeNeighbourInfluenceDegree(uid, followId);
		FriendshipUO friendshipUO = new FriendshipUO();
		friendshipUO.setFollowid(followId);
		friendshipUO.setUid(uid);
		friendshipUO.setInfluenceDegree(influenceDegree);
		friendshipDao.save(friendshipUO);
	}
	
	/**
	 * 获取用户所发微博，最多获取200条
	 * @param uid
	 * @return
	 * @throws WeiboException
	 */
	public List<Status> getAllStatus(String uid){
		User user;
		try {
			user = (new Users()).showUserById(uid);
			List<Status> statuses = new ArrayList<Status>();
			statuses = Status
			.constructStatuses(Weibo.client.get(
					WeiboConfig.getValue("baseURL")
							+ "statuses/user_timeline.json",
					new PostParameter[] {
							new PostParameter("uid", uid.toString()),
							new PostParameter("screen_name", user.getScreenName()),
							new PostParameter("count", "200"),
							new PostParameter("base_app", "0"),
							new PostParameter("feature", "0"),
							new PostParameter("page", "1")}
					));
			for (Status s : statuses) {
				Log.logDebug(s.toString());
			}
			return statuses;
		} catch (WeiboException e) {
		}
		return null;
	}
	
	
	/**
	 * 爬取指定用户的微博，存进数据库
	 * @param uid
	 * @throws WeiboException 
	 */
	public void crawlAllStatus(String uid) throws WeiboException {
		RawStatusUODAO statusDao = new RawStatusUODAO();
//		if (null == statusDao.findByUid(uid)) {
			List<Status> statuses = this.getAllStatus(uid);
			for (Status status : statuses) {
				RawStatusUO statusUO = new RawStatusUO();
				statusUO.setStatus(status);
				statusDao.save(statusUO);
				this.crawlAllComments(status.getId());
				this.crawlAllReposts(status.getId());
			}
//		}
	}
	
	/**
	 * 获取指定微博的评论列表,最多10000条评论
	 * @param sid
	 * @throws WeiboException 
	 */
	public List<Comment> getAllComments(String sid) throws WeiboException {
		List<Comment> allComments = new ArrayList<Comment>();
		int totalCount = (new Timeline()).showStatus(sid).getCommentsCount();
		Paging page = new Paging(1, 200);
		if (totalCount > 10000) {
			totalCount = 10000;
		}
		int cursor = 1;
		for (int cnt = 0; cnt < totalCount; cnt = cnt + 200) {
			page.setPage(cursor++);
			List<Comment> comment = (new Comments()).getCommentById(sid, page, 200, 0);
			allComments.addAll(comment);
			for(Comment c : comment){
				Log.logDebug(c.toString());
			}
		}
		return allComments;
	}
	
	/**
	 * 爬取微博的评论列表，存入数据库
	 * @param sid
	 * @throws WeiboException
	 */
	public void crawlAllComments(String sid) throws WeiboException {
		CommentUODAO commentDao = new CommentUODAO();
//		if (null == commentDao.findBySid(sid)) {
			List<Comment> comments = this.getAllComments(sid);
			for (Comment comment : comments) {
				CommentUO commentUO = new CommentUO();
				commentUO.setCid(comment.getId());
				commentUO.setCreatedAt(comment.getCreatedAt());
				commentUO.setSid(comment.getStatus().getId());
				commentUO.setText(comment.getText());
				commentUO.setUid(comment.getUser().getId());
				commentDao.save(commentUO);
			}
//		}
	}
	
	/**
	 * 获取指定微博的转发列表，最多10000条转发
	 * @param sid
	 * @return
	 * @throws WeiboException
	 */
	public List<Status> getAllReposts(String sid) throws WeiboException {
		Timeline tm = new Timeline();
		List<Status> allReposts = new ArrayList<Status>();
		int totalCount = tm.showStatus(sid).getRepostsCount();
		if (totalCount > 10000) {
			totalCount = 10000;
		}
		Paging page = new Paging(1, 200);
		int cursor = 1;
		for (int cnt = 0; cnt < totalCount; cnt = cnt + 200) {
			page.setPage(cursor++);
			List<Status> reposts = tm.getRepostTimeline(sid, page, 200);
			allReposts.addAll(reposts);
			for (Status r : reposts) {
				Log.logDebug(r.toString());
			}
		}
//		return Status.constructStatuses(Weibo.client.get(
//				WeiboConfig.getValue("baseURL")
//						+ "statuses/repost_timeline.json", new PostParameter[] {
//						new PostParameter("id", sid),
//						new PostParameter("count", "200"),
//						new PostParameter("page", "1")
//						}));

		return allReposts;
	}
	
	/**
	 * 爬取微博的转发列表，存入数据库
	 * @param sid
	 * @throws WeiboException
	 */
	public void crawlAllReposts(String sid) throws WeiboException {
		RepostsUODAO repostsDao = new RepostsUODAO();
//		if (null == repostsDao.findBySid(sid)) {
			List<Status> reposts = this.getAllReposts(sid);
			for (Status r : reposts) {
					Log.logInfo(r.toString());
					if(r.getUser() != null) {
					RepostsUO repostsUO = new RepostsUO();
					repostsUO.setCreatedAt(r.getCreatedAt());
					repostsUO.setRid(r.getId());
					repostsUO.setUid(r.getUser().getId());
					repostsUO.setText(r.getText());
					repostsUO.setSid(sid);
					repostsDao.save(repostsUO);
				}
			}
//		}
	}
		
	public static void main(String [] args) throws WeiboException, IOException{
			Crawler c = new Crawler();
			//c.getAllFollowers("1397095161");
//			c.getAllStatus("1397095161");
//			c.getAllComments("13568035702");

			c.crawlAllFollowers("1704557455");
			c.crawlAllStatus("1704557455");
	}



}
